from flask import Flask, request, jsonify, session
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
import os
import traceback
from datetime import datetime, timedelta
import secrets

app = Flask(__name__)
# 允许跨域请求携带cookie
CORS(app, supports_credentials=True)
app.config['SECRET_KEY'] = secrets.token_hex(16)  # 用于session加密
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(minutes=30)  # session有效期30分钟
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'  # 允许跨域请求携带cookie
app.config['SESSION_COOKIE_HTTPONLY'] = True  # 防止XSS攻击
app.config['SESSION_COOKIE_SECURE'] = False  # 开发环境不需要HTTPS

# 数据库配置参数
HOSTNAME = "127.0.0.1"
PORT = 3306
USERNAME = "root"
DATABASE = "xbj"
PASSWORD = "root"
CHARSET = "utf8"

# 构建数据库连接URI
db_uri = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset={CHARSET}"
app.config['SQLALCHEMY_DATABASE_URI'] = db_uri
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)


# 定义物品模型
class Item(db.Model):
    __tablename__ = 'shuju'  # 指定表名为ABC

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text)
    lost_location = db.Column(db.String(200), nullable=False)
    claim_location = db.Column(db.String(200), nullable=False)
    status = db.Column(db.String(20), default='lost')
    image_url = db.Column(db.String(200))
    created_at = db.Column(db.DateTime, default=datetime.utcnow)


# 定义用户模型
class User(db.Model):
    __tablename__ = 'user'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(100), unique=True, nullable=False)
    password = db.Column(db.String(100), nullable=False)


# 创建表（如果不存在）
with app.app_context():
    try:
        db.create_all()
        print("数据库表创建成功")
    except Exception as e:
        print(f"创建表时出错: {str(e)}")
        traceback.print_exc()

# 管理员账号信息（实际项目中应存储在安全的地方）
ADMIN_USERNAME = "2302091550"
ADMIN_PASSWORD = "xbj666666"


# API路由：管理员登录
@app.route('/api/admin/login', methods=['POST'])
def admin_login():
    try:
        data = request.get_json()
        username = data.get('username')
        password = data.get('password')

        if not username or not password:
            return jsonify({'error': '缺少用户名或密码'}), 400

        if username == ADMIN_USERNAME and password == ADMIN_PASSWORD:
            # 登录成功，设置session
            session['admin'] = True
            session.permanent = True  # 使用上面配置的有效期
            print(f"管理员 {username} 登录成功，session: {session}")
            return jsonify({'message': '登录成功', 'admin': True})
        else:
            print(f"管理员登录失败：用户名 {username}，密码 {password}")
            return jsonify({'error': '用户名或密码错误'}), 401

    except Exception as e:
        traceback.print_exc()
        return jsonify({'error': f'登录失败: {str(e)}'}), 500


# API路由：检查管理员状态
@app.route('/api/admin/status', methods=['GET'])
def admin_status():
    try:
        is_admin = session.get('admin', False)
        print(f"检查管理员状态: {is_admin}，session: {session}")
        return jsonify({'admin': is_admin})
    except Exception as e:
        traceback.print_exc()
        return jsonify({'error': f'检查状态失败: {str(e)}'}), 500


# API路由：管理员登出
@app.route('/api/admin/logout', methods=['POST'])
def admin_logout():
    try:
        print(f"管理员登出前 session: {session}")
        session.pop('admin', None)
        print(f"管理员登出后 session: {session}")
        return jsonify({'message': '登出成功', 'admin': False})
    except Exception as e:
        traceback.print_exc()
        return jsonify({'error': f'登出失败: {str(e)}'}), 500


# API路由：用户注册
@app.route('/api/register', methods=['POST'])
def register():
    try:
        data = request.get_json()
        username = data.get('username')
        password = data.get('password')

        if not username or not password:
            return jsonify({'error': '缺少用户名或密码'}), 400

        existing_user = User.query.filter_by(username=username).first()
        if existing_user:
            return jsonify({'error': '用户名已存在'}), 400

        new_user = User(username=username, password=password)
        db.session.add(new_user)
        db.session.commit()

        return jsonify({'message': '注册成功'}), 201
    except Exception as e:
        db.session.rollback()
        traceback.print_exc()
        return jsonify({'error': f'注册失败: {str(e)}'}), 500


# API路由：用户登录
@app.route('/api/login', methods=['POST'])
def login():
    try:
        data = request.get_json()
        username = data.get('username')
        password = data.get('password')

        if not username or not password:
            return jsonify({'error': '缺少用户名或密码'}), 400

        user = User.query.filter_by(username=username, password=password).first()
        if user:
            session['user'] = username
            session.permanent = True
            return jsonify({'message': '登录成功', 'logged_in': True})
        else:
            return jsonify({'error': '用户名或密码错误'}), 401
    except Exception as e:
        traceback.print_exc()
        return jsonify({'error': f'登录失败: {str(e)}'}), 500


# API路由：检查用户状态
@app.route('/api/user/status', methods=['GET'])
def user_status():
    try:
        logged_in = 'user' in session
        return jsonify({'logged_in': logged_in})
    except Exception as e:
        traceback.print_exc()
        return jsonify({'error': f'检查状态失败: {str(e)}'}), 500


# API路由：用户登出
@app.route('/api/logout', methods=['POST'])
def logout():
    try:
        session.pop('user', None)
        return jsonify({'message': '登出成功', 'logged_in': False})
    except Exception as e:
        traceback.print_exc()
        return jsonify({'error': f'登出失败: {str(e)}'}), 500


# API路由：添加丢失物品
@app.route('/api/items', methods=['POST'])
def add_item():
    try:
        if 'user' not in session:
            return jsonify({'error': '请先登录'}), 401

        data = request.form

        # 处理图片上传
        image_url = None
        if 'image' in request.files:
            image = request.files['image']
            if image.filename != '':
                upload_folder = 'static/images'
                os.makedirs(upload_folder, exist_ok=True)

                # 使用安全的文件名，避免特殊字符
                filename = secrets.token_hex(8) + os.path.splitext(image.filename)[1]
                image_path = os.path.join(upload_folder, filename)
                image.save(image_path)
                image_url = f'/static/images/{filename}'

        new_item = Item(
            name=data['name'],
            description=data.get('description'),
            lost_location=data['lost_location'],
            claim_location=data['claim_location'],
            image_url=image_url
        )

        db.session.add(new_item)
        db.session.commit()

        item_data = {
            'id': new_item.id,
            'name': new_item.name,
            'description': new_item.description,
            'lost_location': new_item.lost_location,
            'claim_location': new_item.claim_location,
            'status': new_item.status,
            'image_url': new_item.image_url,
            'created_at': new_item.created_at.strftime('%Y-%m-%d %H:%M:%S')
        }

        print(f"添加物品成功: {item_data}")
        return jsonify({
            'message': '物品添加成功',
            'item': item_data
        }), 201
    except Exception as e:
        db.session.rollback()
        error_msg = f"添加物品失败: {str(e)}"
        traceback.print_exc()
        return jsonify({'error': error_msg}), 500


# API路由：获取所有物品
@app.route('/api/items', methods=['GET'])
def get_items():
    try:
        # 获取分页参数
        page = request.args.get('page', 1, type=int)
        limit = request.args.get('limit', 10, type=int)
        search = request.args.get('search', '')
        location = request.args.get('location', '')

        query = Item.query

        if search:
            query = query.filter(Item.name.ilike(f'%{search}%'))

        if location:
            query = query.filter(Item.lost_location == location)

        # 按创建时间降序排列
        query = query.order_by(Item.created_at.desc())

        paginated_items = query.paginate(page=page, per_page=limit, error_out=False)

        items = []
        for item in paginated_items.items:
            items.append({
                'id': item.id,
                'name': item.name,
                'description': item.description,
                'lost_location': item.lost_location,
                'claim_location': item.claim_location,
                'status': item.status,
                'image_url': item.image_url,
                'created_at': item.created_at.strftime('%Y-%m-%d %H:%M:%S')
            })

        print(f"获取物品列表: 第 {page} 页，共 {paginated_items.total} 条")
        return jsonify({
            'items': items,
            'total': paginated_items.total,
            'pages': paginated_items.pages,
            'page': paginated_items.page,
            'per_page': paginated_items.per_page
        })
    except Exception as e:
        error_msg = f"获取物品列表失败: {str(e)}"
        traceback.print_exc()
        return jsonify({'error': error_msg}), 500


# API路由：删除物品（需要管理员权限）
@app.route('/api/items/<int:item_id>', methods=['DELETE'])
def delete_item(item_id):
    try:
        # 添加调试日志
        print(f"尝试删除物品 {item_id}，session: {session}")

        # 检查是否为管理员
        if not session.get('admin', False):
            print(f"删除失败：需要管理员权限，当前是否管理员: {session.get('admin', False)}")
            return jsonify({'error': '需要管理员权限'}), 403

        item = Item.query.get(item_id)
        if not item:
            print(f"删除失败：物品 {item_id} 不存在")
            return jsonify({'error': '物品不存在'}), 404

        # 删除相关图片文件
        if item.image_url and 'static/images' in item.image_url:
            try:
                # 确保路径安全，防止目录遍历攻击
                image_path = os.path.join(app.root_path, item.image_url.lstrip('/'))
                if os.path.exists(image_path):
                    os.remove(image_path)
                    print(f"已删除图片: {image_path}")
            except Exception as e:
                print(f"删除图片失败: {str(e)}")

        db.session.delete(item)
        db.session.commit()

        print(f"物品 {item_id} 删除成功")
        return jsonify({'message': '物品删除成功'})
    except Exception as e:
        db.session.rollback()
        error_msg = f"删除物品失败: {str(e)}"
        traceback.print_exc()
        return jsonify({'error': error_msg}), 500


if __name__ == '__main__':
    app.run(debug=True)